import { Injectable } from '@nestjs/common';
import { Iccard } from 'src/entities/Iccard';
import { IccardChargeOrder } from 'src/entities/IccardChargeOrder';
import { IccardFinanceLog } from 'src/entities/IccardFinanceLog';
import { IccardModelService } from 'src/model/iccard-model/iccard-model.service';
import { RedisService } from 'src/redis/redis.service';
import { getTime } from 'src/util';
import { Connection } from 'typeorm';
import { DeviceService } from '../device/device.service';

@Injectable()
export class IccardService {
    constructor(
        private iccardModelService:IccardModelService,
        private deviceService:DeviceService,
        private connection: Connection,
        private redis:RedisService
    ){}

    async balance(cardNo) {
        const card = await this.iccardModelService.findOne({ cardNo }, ['amount', 'rewardAmount', 'status'])
        if(!card) {
            return null
        }
        return {
            balace : (Number(card.amount) + Number(card.rewardAmount)) * 100,
            status : card.status
        }
    }

    async charge(simcardNo:string, cardNo:string, portNo:number) {
        const lockKey = 'c:' + cardNo
        if((await this.redis.set(lockKey, '', 'EX', 10, 'NX')) == false) return false

        let returnData:any = {
            error : '00'
        }

        const card = await this.iccardModelService.findOne({ cardNo }, ['id', 'userId', 'amount', 'rewardAmount', 'status'])
        if(!card) { //卡不存在
            returnData.error = '01'
            return returnData
        }

        if(card.status != 1) {
            if(card.status == 0) { //未激活
                returnData.error = '06'
            }else if(card.status == 0) { //挂失
                returnData.error = '01'
            }else if(card.status == 3){ //黑名单
                returnData.error = '05'
            }

            return returnData
        }

        
        let device = await this.deviceService.getDeviceSimCardNo(simcardNo)
        if(!device || !device.strategyId) {
            returnData.error = '03'
            return returnData
        }
        const strategy = await this.deviceService.strategy(device.strategyId)
        if(!strategy) {
            returnData.error = '03'
            return returnData
        }

        let rechargeBalance = Number(card.amount) //充值的余额
        let rewardBalance = Number(card.rewardAmount) //赠送的余额

        const amount = Number(strategy.cardChargeAmount)

        if((rechargeBalance + rewardBalance) < amount) { //余额不足
            returnData.error = '02'
            return returnData
        }

        const time = getTime()

        const orderNo = time + '' + card.userId

        let orderData:{[key in keyof IccardChargeOrder]? : IccardChargeOrder[key]} = {
            cardNo : cardNo,
            cardId : card.id,
            userId : card.userId,
            orderNo : orderNo,
            deviceId : device.deviceId,
            portNo : portNo,
            feeAmount : '0',
            feeRewardAmount : '0',
            chargeAmount : String(amount),
            strategyRules : strategy.rules,
            strategyType : strategy.strategyType,
            unitPrice : strategy.unitPrice,
            settleUnit : strategy.settleUnit,
            createTime : time
        }

        if(device.merchantId) {
            orderData.merchantId = device.merchantId
        }

        const queryRunner = this.connection.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction()

        try {
            let cardUpdate:{amount? : string, rewardAmount? : string} = {}
            let cardFinanceLog:{[key in keyof IccardFinanceLog]? : IccardFinanceLog[key]} = {
                beforeAmount : card.amount,
                beforeRewardAmount : card.rewardAmount,
                type : 2,
            }

            if(rechargeBalance >= amount) { //充值余额够钱
                orderData.feeAmount = orderData.chargeAmount //充电订单中充值余额支出部分
                cardUpdate.amount = String(rechargeBalance - amount) //钱包充值余额，更新钱包
                

                cardFinanceLog.amount = String(-amount) //余额部分支付的
                //支出之后钱包的余额记录
                cardFinanceLog.afterAmount = cardUpdate.amount
                cardFinanceLog.afterRewardAmount = card.rewardAmount //赠送余额不变
            }else {
                let offset = amount - rechargeBalance
                
                orderData.feeRewardAmount = String(offset) //充电订单中赠送余额支出部分
                cardUpdate.rewardAmount = String(rewardBalance - offset) //钱包赠送余额，更新钱包
                
                cardFinanceLog.rewardAmount = String(-offset)  //赠送余额支出部分

                //支出之后钱包的赠送余额记录
                cardFinanceLog.afterRewardAmount = cardUpdate.rewardAmount

                if(rechargeBalance > 0) { //如果充值余额有钱的
                    orderData.feeAmount = String(rechargeBalance) //充值余额全部给出
                    cardUpdate.amount = '0' //钱包充值余额，更新钱包

                    cardFinanceLog.amount = String(-rechargeBalance)
                    cardFinanceLog.afterAmount = cardUpdate.amount
                }

            }

            {
                //更新卡余额
                const { raw } = await queryRunner.manager.update<Iccard>(Iccard, { id : card.id }, cardUpdate)
                if(!raw || raw.affectedRows < 1) {
                    await queryRunner.rollbackTransaction()
                    return false
                }
            }

            let orderId = 0

            {
                //加入订单
                const { raw } = await queryRunner.manager.insert<IccardChargeOrder>(IccardChargeOrder, orderData)
                if(!raw || raw.affectedRows < 1) {
                    await queryRunner.rollbackTransaction()
                    return false
                }
                cardFinanceLog.relationId = orderId = raw.insertId
            }

            {
                //加入收支明细
                cardFinanceLog.createTime = time
                const { raw } = await queryRunner.manager.insert<IccardFinanceLog>(IccardFinanceLog, cardFinanceLog)
                if(!raw || raw.affectedRows < 1) {
                    await queryRunner.rollbackTransaction()
                    return false
                }
            }

            returnData.orderNo = orderId
            returnData.balance = Number(((rechargeBalance + rewardBalance) - amount).toFixed(2))
            await queryRunner.commitTransaction()

            return returnData


        } catch (error) {
            await queryRunner.rollbackTransaction()
        }finally {
            
            await queryRunner.release()
        }

        return false
    }
}
